home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_12_07
/
storn2
/
cck.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-11
|
162KB
|
3,087 lines
/**C*M****************************************************************
** **
** MODULE_NAME : cck.c **
** VERSION : 1.1 **
** DATE : October 93 **
** LONG_NAME : C Conventions checker **
** **
** **
** SP_NO : C-coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : This program has been written to provide a tool **
** for checking C coding conventions (please see **
** the corresponding contribution in the C Users **
** Journal in 1994). The program has been developed **
** by using the Microsoft C compiler version 6.0. **
** **
** REMARKS : cck may be used for any commercial and non- **
** commercial purpose. If you want to modify the **
** program to fit your requirements feel free to do **
** so but you should make a reference to our **
** original source code or to the above paper. **
** If you like the program we would be glad to **
** receive a symbolic appreciation of $1. A few lines **
** containing your opinion on our program or sugge- **
** stions for improvements will do as well. **
** Please send your contribution to the following **
** address: **
** Rainer Storn **
** Schlehenring 20a **
** D-85551 Kirchheim b. Muenchen **
** Germany **
** **
** FUNCTIONS : see function prototypes section **
** MODULES : none, this is a single module program. **
** **
***C*M*E*************************************************************/
/**H*O*C**************************************************************
** **
** No.!Version! Date ! Request ! Modification ! Author **
** ---+-------+------+---------+---------------------------+------- **
** 1 + 001 +9/9/93+ - + change c=getchar() into + Storn **
** + + + + c=(CHAR)getchar() in main(). **
** 2 + 001 +9/15/93+ - + adjusted *false_ptr[] in + Storn **
** + + + + ptr_name(). + **
** 3 + 001 +9/15/93+ - + adjusted *pat_bis[] and + Storn **
** + + + + *false_ptr[] in right_place(). **
** 4 + 001 +9/15/93+ - + included a "busy"-indicator+ Storn **
** 5 + 001 +9/16/93+ - + changed or added several + Storn **
** + + + + comments. + **
** 6 + 001 +9/16/93+ - + checked return value of + Storn **
** + + + + malloc() in find_keyword().+ **
** 1 + 1.0 +9/17/93+ - + changed { into } in some + Storn **
** + + + + places of *pattern_ptr[] + **
** + + + + in right_place(). + **
** 2 + 1.0 +9/22/93+ - + separator @(BAR) included.+ Storn **
** + + + + This affected compile(), + **
** + + + - + part_match() + **
** 3 + 1.0 +9/24/93+ - + Did some speedup by intro-+ Storn **
** + + + + ducing bar_flg in compile()+ **
** + + + + and part_match() and mode + **
** + + + + in part_match(). + **
** 4 + 1.0 +10/2/93+ - + removed global pointer + Storn **
** + + + + save2_ptr and used local + **
** + + + + pointers save2_pptr and + **
** + + + + save3_pptr instead. + **
** 5 + 1.0 +10/2/93+ - + corrected some patterns in+ Storn **
** + + + + right_place(). It is not + **
** + + + + good to place a star im- + **
** + + + + mediately after a class. + **
** 6 + 1.0 +10/2/93+ - + placed reinitialization + Storn **
** + + + + section into BAR-part of + **
** + + + + part_match(). + **
** 7 + 1.0 +10/3/93+ - + added the requirement that+ Storn **
** + + + + pointer to pointer should + **
** + + + + either be replaced by in- + **
** + + + + dex notation or have the + **
** + + + + suffix _pptr. + **
** **
***H*O*C*E***********************************************************/
/*----------------------------------------------------------------------
-----------------------------Includes-----------------------------------
----------------------------------------------------------------------*/
#include "stdlib.h"
#include "stdtyp.h"
#include "stdio.h"
#include "string.h"
#include "ctype.h"
/*----------------------------------------------------------------------
------------------------External Functions------------------------------
----------------------------------------------------------------------*/
/*----------------------------------------------------------------------
---------------Global declarations--------------------------------------
----------------------------------------------------------------------*/
#define FILEN 250000 /* No.of CHARs in file */
#define LINLEN 150 /* assumed maximum line */
/* length. */
#define PMAX 256 /* max size of pattern */
/* for one keyword */
#define M_NCLMAX 3000 /* max of non comment lines*/
/* in a module */
#define F_NCLMAX 200 /* max of non comment lines*/
/* in a function */
#define BR_ERROR 0
/* all those defined values must fit in one character */
/* variable. They will be used to easen the task of */
/* pattern searching. */
#define ACHAR 1 /* a character */
#define BOL 2 /* beginning of a line */
#define EOL 3 /* end of line */
#define ANY 4 /* any char but new-line */
#define CLASS 5 /* in the following class */
#define NCLASS 6 /* not in the following class */
#define STAR 7 /* zero or more occurences */
#define PLUS 8 /* one or more occurences */
#define MINUS 9 /* zero or one occurence */
#define NALPHA 10 /* any alphanumeric */
#define VAR 11 /* any char of a var name */
#define RANGE 12 /* in range of the 2 next char*/
#define ENDPAT 13 /* end of pattern */
#define BAR 14 /* logical or */
/*----------------------------------------------------------------------
-----------------Typedefs-----------------------------------------------
----------------------------------------------------------------------*/
typedef struct
/*****************************
** **
** Location of keywords in **
** source_file[]. **
** **
*****************************/
{
CHAR *end_ptr; /* end of keyword */
LONG line_no; /* corresponding line number. */
}T_LOCA;
/*----------------------------------------------------------------------
-----------------Global variables---------------------------------------
----------------------------------------------------------------------*/
CHAR source_file[FILEN]; /* Holds source file. source_file[] */
/* must be global in order to allow */
/* a huge value for FILEN (at least for */
/* Microsoft C 6.0 for DOS). */
/*----------------------------------------------------------------------
-----------------------function prototypes------------------------------
----------------------------------------------------------------------*/
void main(SHORT argc, CHAR *argv[]);
LONG read_file(CHAR source_file[], CHAR *argv[]);
LONG braces_etc(CHAR source_file[], LONG nb_line, FILE *fout_ptr, CHAR *argv[]);
void compile(CHAR *source_ptr, CHAR pbuf[]);
CHAR *comp_class(CHAR *source_ptr, CHAR *cl_st_ptr, CHAR pbuf[], CHAR *p_ptr, CHAR **save3_pptr);
void store(CHAR op, CHAR pbuf[], CHAR *p_ptr);
T_LOCA find_keyword(CHAR *start_ptr, LONG line_st, LONG line_end, CHAR pbuf[]);
CHAR *part_match(CHAR *start_ptr, CHAR pattern[], LONG *l_ptr, CHAR **save2_pptr, CHAR mode);
void forbidden_keyword(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void right_place(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void user_type_name(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void ptr_name(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void switch_stat(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void default_stat(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void tst_loop(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void lib_fct_call(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void val_and_ad(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
void miscellaneous(CHAR source_file[], LONG nb_line, FILE *fout_ptr);
T_LOCA recurs(T_LOCA l_switch, LONG nb_line, CHAR psw[], CHAR pdef[], FILE *fout_ptr);
/*----------------------------------------------------------------------
-----------------------function definitions-----------------------------
----------------------------------------------------------------------*/
void main(SHORT argc, CHAR *argv[])
/**C*F****************************************************************
** **
** SRC-MODULE : main **
** VERSION : 001 **
** LONG_NAME : main **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM-TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION :Main reads an input file, does some parsing and **
** writes the results on an output file. Both file- **
** names must be provided when calling cck. **
** Calling syntax is:"cck <input-file> <output- **
** file>". Note that the filenames must be complete **
** i.e. if the input file is "test.c" the name must **
** be "test.c" and not just "test" as it is common **
** practice in application programs. **
** **
** REMARKS :- **
** **
** FUNCTIONS : printf(), exit(), strstr(), fopen(), getchar() **
** fopen(), fclose(), fprintf(), read_file(), **
** braces_etc(), forbidden_keyword(), right_place()**
** user_type_name(), ptr_name(), switch_stat(), **
** tst_loop(), lib_fct_call(), unsgn_shift(), **
** val_and_ad(), micellaneous() **
** **
** GLOBALS : see globals declaration section for explanation **
** **
** PARAMETERS :argc : holds the number of arguments in the **
** command line (3 in this case). **
** argv : points to an array of strings. argv[0] **
** for example points to the first string **
** which must be "cck". **
** **
** PRECONDITIONS : there must be a C source file <input_file> **
** which ideally should have passed compilation **
** without warnings (however this is not necessary)**
** **
** POSTCONDITIONS : an output file will be generated that produces **
** a list of warnings concerning the Coding **
** Conventions. For the Coding Conventions see **
** "Coding Conventions for C-SW Projects", **
** Dr. Rainer Storn, ZFE ST ACK 21. **
** **
** **
***C*F*E*************************************************************/
{
FILE *fout_ptr; /* Pointer to output file. */
LONG nb_line; /* Line counter */
LONG nc_line; /* Number of noncomment lines */
CHAR *c_ptr;
CHAR c;
/*------Check arguments-------------------------------------------------*/
if (argc NEQ 3) /* number of arguments */
{
printf("\nUsage : cck <input-file> <output-file>\n");
exit(1);
}
c_ptr = strstr(argv[2],".c"); /* look for .c in output file name */
if (( c_ptr NEQ NULL ) AND ( *(c_ptr+2) EQ '\0'))
{
printf("\nUsage : cck <input-file> <output-file>\n");
printf("The output file is not a C file, hence its name shall not end with .c \n");
exit(1);
}
fout_ptr = fopen(argv[2],"r"); /* NULL if output file does */
/* already exist */
if ( fout_ptr NEQ NULL )
{
printf("\nOutput file %s does already exist, type y if you ",argv[2]);
printf("want to overwrite it, anything else if you want to exit.\n");
c = (CHAR)getchar();
if ( c NEQ 'y')
exit(1);
}
(void)fclose(fout_ptr);
/*----- Initialize variables --------------------------------------------*/
nb_line = 0; /* set counters to zero */
nc_line = 0;
/*-----Establish output file---------------------------------------------*/
fout_ptr = fopen(argv[2],"w"); /* Open Output file for writing */
if (fout_ptr EQ NULL)
{
printf("\nCannot open output file\n");
exit(1); /* output file is necessary */
}
(void)fclose(fout_ptr); /* Close output file. */
/*----- Read input file -------------------------------------------------*/
/*----- (replace '\n' by '\0' and return nb of lines of source_file) ----*/
printf("Please wait until the figure 11 has appeared.\n");
nb_line = read_file(source_file, argv);
/*-----Check braces, brackets, parens and comments-----------------------*/
nc_line = braces_etc(source_file, nb_line, fout_ptr, argv);
printf("1 ");
if ( nc_line NEQ BR_ERROR )
{
if ( nc_line > M_NCLMAX )
{
fprintf(fout_ptr, "\nWARNING : the size of this module is %ld noncommented lines ",nc_line);
fprintf(fout_ptr, "\n more than the maximum size %ld ! ", M_NCLMAX );
}
/*---- Check presence of forbidden keywords -------------------------*/
(void)forbidden_keyword(source_file, nb_line, fout_ptr);
printf("2 ");
/*---- Check place of attributes like typedef... --------------------*/
(void)right_place(source_file, nb_line, fout_ptr);
printf("3 ");
/*---- Check names of user defined types ----------------------------*/
(void)user_type_name(source_file, nb_line, fout_ptr);
printf("4 ");
/*---- Check that pointers names end with _ptr ----------------------*/
(void)ptr_name(source_file, nb_line, fout_ptr);
printf("5 ");
/*---- Check switch statements --------------------------------------*/
(void)switch_stat(source_file, nb_line, fout_ptr);
printf("6 ");
(void)default_stat(source_file, nb_line, fout_ptr);
printf("7 ");
/*---- Tests in while and if loops ----------------------------------*/
(void)tst_loop(source_file, nb_line, fout_ptr);
printf("8 ");
/*---- Return values checked before use -----------------------------*/
(void)lib_fct_call(source_file, nb_line, fout_ptr);
printf("9 ");
/*---- Value and address of an object in the same line --------------*/
(void)val_and_ad(source_file, nb_line, fout_ptr);
printf("10 ");
/*---- Miscellaneous ------------------------------------------------*/
(void)miscellaneous(source_file, nb_line, fout_ptr);
printf("11\n");
(void)fclose(fout_ptr);
}
}
LONG read_file(CHAR source_file[], CHAR *argv[])
/**C*F****************************************************************
** **
** SRC-FUNCTION :read_file **
** VERSION :001 **
** LONG_NAME :read_file **
** **
** SPECIFICATION :C Coding Conventions **
** SUBSYSTEM :- **
** SYSTEM-TYPE :PCD-3T **
** **
** AUTHOR :Dr. Rainer Storn **
** SUBSTITUTE :Helene Ballay **
** **
** DESCRIPTION :read_file opens the file specified by argv[1], **
** reads it, and stores it into the character array **
** source_file[]. While doing this, all '\n' are **
** transformed into '\0' so that source_file[] will **
** contain a collection of adjacent strings which **
** can be treated by the string processing fun- **
** ctions in string.h. The number of strings, **
** nb_line, will be returned by read_file(). **
** **
** REMARKS :- **
** **
** FUNCTIONS :printf(), exit(), fopen(), fclose(), getc(), **
** feof() **
** **
** GLOBALS :source_file[] **
** **
** PARAMETERS :argv : here only argv[1] is used which points to **
** the input file. For more infomation see **
** declaration in main(). **
** **
** PRECONDITIONS :- **
** **
** POSTCONDITIONS :if input file is available, its content will be **
** in source_file[] with all '\n' replaced by '\0'. **
** If the input file was too long, source_file[] **
** will contain a troncated version and a warning **
** message will be printed on the standard output. **
** **
** **
***C*F*E*************************************************************/
{
FILE *fin_ptr; /* File pointer to input file.*/
CHAR ch_buffer; /* intermediate buffer */
CHAR eof_flag; /* turns 1 on EOF, 0 otherwise*/
LONG i; /* Universal counter */
LONG nb_line; /* Number of lines */
/*------ Open input file -----------------------------------------------*/
fin_ptr = fopen(argv[1],"r"); /* Open input file for reading */
if (fin_ptr EQ NULL)
{
printf("\nCannot open input file in read_file()\n");
exit(1);
}
/*----- Read source file and change all returns (\n) into ---------------*/
/*----- string delimiters (\0) ------------------------------------------*/
for (i=0; i<FILEN; i++)
{
source_file[i] = ' '; /* initialize array s[] with blanks */
}
source_file[FILEN-1] = '\0'; /* indicate end of array with '\0' */
ch_buffer = (CHAR)getc(fin_ptr); /* Read first character */
i = 0; /* initialize file length counter */
nb_line = 0; /* initialize line counter */
eof_flag = 0; /* Reset eof_flag to "no EOF" */
/*------Keep on reading as long as there is something to read and--------*/
/*------there is still space left in source_file[].----------------------*/
while ((source_file[i] NEQ '\0') AND ( eof_flag NEQ 1 ))
{
if (ch_buffer EQ '\n')
{
ch_buffer = '\0'; /* Convert newline into string delimiter */
nb_line++; /* increment line counter */
}
source_file[i] = ch_buffer;
i++;
ch_buffer = (CHAR)getc(fin_ptr); /* read next character */
if ( feof(fin_ptr) NEQ 0)
{
eof_flag = 1; /* set eof_flag to "EOF found" */
source_file[i] = '\0'; /* Indicate EOF with \0 */
}
}
if (eof_flag EQ 0)
{
printf("\nInput file is too large for input buffer source_file[]\n");
(void)fclose(fin_ptr);
exit(1);
}
(void)fclose(fin_ptr); /* close input file */
return(nb_line);
}
LONG braces_etc(CHAR source_file[], LONG nb_line, FILE *fout_ptr, CHAR *argv[])
/**C*F*******************************************************************
** **
** SRC-MODULE : braces_etc **
** VERSION : 001 **
** LONG_NAME : braces_etc **
** **
** SPECIFICATION : this program is based on CC.C by T. Jennings and **
** David N. Smith, public domain program CUG152.15 **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : braces_etc() checks the brackets, comments, **
** parens and doublequotes by counting them in **
** source_file[] and printing the result in the file **
** pointed to by fout_ptr. It skips over all char **
** within comments or doublequoted text and does not **
** count quoted characters. The number of lines with **
** "not just comments" inside, ncline, will be re- **
** turned. **
** **
** REMARKS : **
** **
** FUNCTIONS : fopen(), printf(), exit(), fclose(), fprintf(), **
** return() **
** **
** GLOBALS : source_file[] **
** **
** PARAMETERS : nb_line : number of lines of source_file[] **
** fout_ptr: points to the output file **
** argv[] : argv[2] points to the third string of **
** the line command ie the output file name **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
register CHAR *c_ptr; /* current character */
CHAR lastc; /* last character */
CHAR nextc; /* next character */
LONG parens; /* counts opened parens */
LONG brackets; /* counts opened brackets */
LONG comment; /* counts opened comments */
LONG dblequote; /* counts opened dblequotes */
LONG line; /* current line of entire file */
LONG ncline; /* counts non empty lines with "not just */
/* comments" (entire file) */
LONG fline; /* counts non empty lines of current function */
LONG fncline; /* counts non empty lines with "not just */
/* comments" (current function) */
LONG fcline; /* counts comment lines of current function */
/* with or without noncomment C code. */
CHAR *str_ptr; /* string (line) pointer */
LONG sth; /* counts anything else than spaces or com- */
/* ments or quoted text (used to recognize */
/* ncline ) */
LONG message; /* flag indicating that a warning happened */
/*------Open output file for appending information-------------------------------*/
fout_ptr=fopen(argv[2],"a");
if (fout_ptr EQ NULL)
{
printf("\nCannot open output file in braces_etc()\n");
exit(1); /* output file is needed */
}
/*-----Initialize variables------------------------------------------------------*/
parens = 0; /* set initial value 0 to all counters */
brackets = 0; /* set initial value 0 to all counters */
comment = 0; /* set initial value 0 to all counters */
dblequote = 0; /* set initial value 0 to all counters */
line = 0; /* set initial value 0 to all counters */
ncline = 0; /* set initial value 0 to all counters */
fline = 0; /* set initial value 0 to all counters */
fncline = 0; /* set initial value 0 to all counters */
fcline = 0; /* set initial value 0 to all counters */
sth = 0; /* set initial value 0 to all counters */
message = 0;
c_ptr = source_file; /* read first character */
lastc = 'a'; /* dummy value */
nextc = 'a'; /* dummy value */
str_ptr = source_file; /* points to first char */
/*----Examine source_file -------------------------------------------------------*/
while ( nb_line > line) /* still are unexamined lines */
{
/*------- skip over comments -----------------------------------------------*/
if ((lastc EQ '/') AND ( *c_ptr EQ '*')) /* if there is a comment */
{
comment++;
fcline++;
do /* go to end of comment */
{
lastc = *c_ptr;
c_ptr++;
if ( *c_ptr EQ '\0') /* printing ended lines */
{
line++;
fcline++;
fline++;
fprintf(fout_ptr,"\nline %4ld: {%2ld} (%2ld) /*%2ld*/ \"%2ld\" ",line,brackets,parens,comment,dblequote);
fprintf(fout_ptr,"%s ", str_ptr);
str_ptr = c_ptr + 1; /* next line */
}
}while (((lastc NEQ '*') OR ( *c_ptr NEQ '/')) AND( nb_line >= line));
if ( line > nb_line) /* if end of file reached */
continue; /* go back to while loop */
comment--; /* if end of comment reached */
lastc = *c_ptr;
c_ptr++;
nextc = *(c_ptr + 1);
continue; /* and let's start again... */
} /* (go back to while loop) */
/*------- skip over text between double quotes -----------------------------*/
/*------- (same principle as above)-----------------------------------------*/
else if (( *c_ptr EQ '"') AND ((lastc NEQ '\'') OR (nextc NEQ '\'')) )
{
dblequote++;
do /* go to end of quoted text */
{
lastc = *c_ptr;
c_ptr++;
if (*c_ptr EQ '\0') /* printing finished lines */
{
line++;
ncline++;
fline++;
fncline++;
fprintf(fout_ptr,"\nline %4ld: {%2ld} (%2ld) /*%2ld*/ \"%2ld\" ",line,brackets,parens,comment,dblequote);
fprintf(fout_ptr," %s ", str_ptr);
str_ptr = c_ptr + 1; /* next line */
}
}while ( (( *c_ptr NEQ '"' ) OR (lastc EQ '\\')) AND ( nb_line > line) );
if ( line > nb_line ) /* if end of file reached */
continue; /* go back to while loop */
dblequote--; /* if end of quoted text reached */
lastc = *c_ptr;
c_ptr++;
nextc = *(c_ptr +1);
continue; /* and let's start again... */
} /* (go back to while loop) */
/*------- Brackets and parens -----------------------------------------------*/
else if (( *c_ptr EQ '{') OR ( *c_ptr EQ '}') OR ( *c_ptr EQ '(') OR ( *c_ptr EQ ')'))
{
if (( nextc NEQ '\'') OR (lastc NEQ '\'')) /* only non quoted ones */
{
if ( *c_ptr EQ '{') /* If bracket opened */
{
brackets++;
if (brackets EQ 1) /* if start of a function */
{
fline = 0; /* reset all function counters */
fcline = 0;
fncline = 0;
}
}
if ( *c_ptr EQ '}') /* If bracket closed */
{
brackets--;
if (brackets EQ 0) /* if end of a function */
{
if (fncline > F_NCLMAX) /* if function too long */
{
message++;
fprintf(fout_ptr,"\n\nWARNING (line %4ld): This function contains %ld non comment lines of code.",line,fncline);
fprintf(fout_ptr,"You shouldn't use more than %d.\n",F_NCLMAX);
}
if (fcline < (LONG)(.2 * (float)(fline)) ) /* if function not enough commented */
{
message++;
fprintf(fout_ptr,"\n\nWARNING (line %4ld): this function has only %ld comment lines",line,fcline);
fprintf(fout_ptr," for %ld lines of code, please use at least %ld comment lines (20%%).\n",fline,(LONG)(.2 * (float)(fline)));
}
}
}
if ( *c_ptr EQ '(') /* if parens opened */
parens++;
if ( *c_ptr EQ ')') /* if parens closed */
parens--;
}
}
/*------- Unexpected end of comment ----------------------------------------*/
if ((lastc EQ '*') AND ( *c_ptr EQ '/'))
comment--;
/*------ End of line: print the line with the values of the counters -------*/
if ( *c_ptr EQ '\0')
{
line++;
if (*(c_ptr-1) NEQ '\0') /* counts only non empty lines */
{
fline++;
if (sth NEQ 0) /* a noncomment line must contain something */
{ /* else than comment and space */
fncline++;
ncline++;
}
}
fprintf(fout_ptr," \nline %4ld: {%2ld} (%2ld) /*%2ld*/ \"%2ld\" ",line,brackets,parens,comment,dblequote);
fprintf(fout_ptr," %s ", str_ptr);
str_ptr = c_ptr + 1; /* next line */
sth = 0; /* reset counter */
}
/*------ Next character, please ! ------------------------------------------*/
lastc = *c_ptr;
if ((lastc NEQ '\0') AND (lastc NEQ ' ') AND (lastc NEQ '/') AND (lastc NEQ '"'))
sth++;
c_ptr++;
nextc = *(c_ptr +1);
}
/*--------- Warning messages --------------------------------------------------*/
if ( (comment EQ 0) AND (dblequote EQ 0) AND (brackets EQ 0) AND (parens EQ 0))
{
if (message EQ 0) /* if braces_etc printed no warning */
{
(void)fclose(fout_ptr); /* close output file */
fout_ptr = fopen(argv[2],"w"); /* reopen output file, text printed */
/* there by braces_etc is lost */
if (fout_ptr EQ NULL)
{
printf("\nCannot re-open output file\n");
exit(1); /* output file is needed */
}
}
else
{
fprintf(fout_ptr,"\n\nWARNING : %ld function(s) of this program is(are) not ",message);
fprintf(fout_ptr,"enough commented, see listing above for details. \n");
}
return(ncline);
}
else
{
if (comment NEQ 0)
fprintf(fout_ptr, "\n\n UNBALANCED COMMENTS !");
if (dblequote NEQ 0)
fprintf(fout_ptr, "\n\n UNBALANCED DOUBLE QUOTES !");
if (brackets NEQ 0)
fprintf(fout_ptr, "\n\n UNBALANCED BRACKETS !");
if (parens NEQ 0)
fprintf(fout_ptr, "\n\n UNBALANCED PARENS !");
(void)fclose(fout_ptr);
return(BR_ERROR); /* other tests will not be executed */
}
}
T_LOCA find_keyword(CHAR *start_ptr, LONG line_st, LONG line_end, CHAR pbuf[])
/**C*F*******************************************************************
** **
** SRC-MODULE : find_keyword **
** VERSION : 001 **
** LONG_NAME : find_keyword **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : find_keyword() scans source_file[] starting at **
** start_ptr (line_st) until the beginning of line_end**
** for the pattern already compiled in pbuf[] ( see **
** function compile() ), by calling part_match(). **
** it goes one char further if no match is found, **
** or skip over quoted text or comment. (in this case,**
** part_match will have put the end of text to skip **
** in *save2_pptr ). find_keyword will return the **
** first location found, (NULL,0) if none. **
** **
** REMARKS : **
** **
** FUNCTIONS : malloc(), part_match(), return() **
** **
** GLOBALS : **
** **
** PARAMETERS : start_ptr points to the char in source_file where **
** the search shall begin. **
** line_st number of the line in source_file[] to **
** start the search. **
** line_end number of the line in source_file[] to **
** end the search. **
** pbuf[] array contains the pattern to match **
** **
** PRECONDITIONS : pbuf[] must be compiled ( by compile() ) before **
** **
** POSTCONDITIONS : returns the location of the first match found or **
** (NULL, 0) if no match. *save2_pptr is NULL at the **
** end. **
** **
** **
***C*F*E****************************************************************/
{
T_LOCA location; /* location of keyword */
register LONG *l_ptr; /* current line */
/* a pointer is used because the value*/
/* will be changed by part_match() */
CHAR *st_ptr; /* beginning of the partial search */
CHAR *pl_ptr; /* place found by part_match() */
CHAR **save2_pptr; /* *save2_pptr is used to know the */
/* end of text being skipped by */
/* part_match(). */
CHAR *anchor_ptr; /* serves just as a defined location */
/* in memory. */
/*--------- Initialize variables -----------------------------------------------*/
st_ptr = start_ptr; /* beginning of the search */
pl_ptr = NULL; /* no match found */
save2_pptr = &anchor_ptr; /* initialize save2_pptr to a defined value. */
*save2_pptr = NULL; /* no text to skip */
l_ptr = (LONG *)malloc(1*sizeof(LONG));
if (l_ptr EQ NULL)
{
printf("\nmalloc() failed in function find_keyword()\n");
exit(1);
}
*l_ptr = line_st; /* first line */
location.end_ptr = NULL; /* "keyword not found (yet)*/
location.line_no = 0; /* "keyword not found (yet)*/
/*--------- Scan source_file starting at start_ptr for the pattern in pbuf -----*/
if (*st_ptr EQ '\0') /* if search starts at the end of a line */
(*l_ptr)++;
pl_ptr = part_match(st_ptr, pbuf, l_ptr, save2_pptr, 1);
while (( *l_ptr < line_end) AND ( pl_ptr EQ NULL))
{
if (*save2_pptr NEQ NULL ) /* if part_match() has found text to skip */
{
st_ptr = *save2_pptr; /* skip over it */
*save2_pptr = NULL; /* no text to skip */
}
st_ptr++; /* next character in source_file[] */
if ( *st_ptr EQ '\0') /* if end of a line reached */
{
(*l_ptr)++;
}
pl_ptr = part_match(st_ptr, pbuf, l_ptr, save2_pptr, 1);
}
if (pl_ptr NEQ NULL) /* if keyword found */
{
location.line_no = *l_ptr;
location.end_ptr = pl_ptr;
}
return(location);
}
void compile(CHAR *source_ptr, CHAR pbuf[PMAX])
/**C*F*******************************************************************
** **
** SRC-MODULE : compile **
** VERSION : 001 **
** LONG_NAME : compile **
** **
** **
** SPECIFICATION : this program is based on grep.c by David N. Smith **
** public domain program CUG152.08 **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : compile() compiles the regular expressions starting**
** at source (for further explanation about regular **
** expression see comment just after this header ) it **
** stores it in pbuf[] using the patterns already **
** defined (ACHAR, .... ENDPAT) in global declarations**
** (see postconditions for further explanation ) **
** so that part_match() can use it for finding matches**
** **
** REMARKS : Note that pbuf[0] contains a flag (bar_flg) which **
** indicates the appearance of '@' in the pattern **
** string. **
** Note that the pattern in pbuf[] does not end with **
** ENDPAT but with 0 because ENDPAT can appear several**
** times in pbuf[]. **
** **
** FUNCTIONS : store(), printf(), comp_class() **
** **
** GLOBALS : **
** **
** PARAMETERS : source_ptr: source_ptr points to the pattern to be **
** translated in a regular expression. **
** pbuf[]: pattern template **
** **
** PRECONDITIONS : the string pointed to by source must be written **
** following the notation of regular expression **
** explained below. **
** **
** POSTCONDITIONS : pbuf contains the pattern template, a string of **
** characters, ending with 0, a concatenation of **
** part patterns. **
** Each part pattern starts with the constant for the **
** number of occurences (MINUS, PLUS, STAR or none if **
** it shall match one time). Then the nature of the **
** character to match (BOL, EOL, ANY, NALPHA, VAR), **
** or the nature of the character and the character **
** itself for ACHAR. It ends with ENDPAT. See **
** comp_class() header for explanations about classes.**
** If the pattern isn't a regular expression, a **
** warning message will be printed on the standard **
** output and the program stops. **
** **
** **
***C*F*E****************************************************************/
/*********************************************************************************************
** **
** The patterns describing the classes of strings to be searched for are written using **
** regular expressions with the following notation : **
** **
** habit A string of text characters with no operators at all ( ie none of those **
** mentionned below) matches the literal string. **
** fo* An expression followed by a star matches zero or more occurence of that **
** expression : "fo*" matches "f", "fo", "foo" etc. **
** fo- An expression followed by a minus sign optionally matches the expression : **
** "fo-" matches "f" and "fo". **
** fo+ An expression followed by a plus sign matches one or more occurence of this **
** expression : "fo+" matches "fo", "foo" etc. **
** ^fo A circumflex followed by a pattern signifies that the pattern must match at **
** the beginning of a line. **
** ab$ A dollar sign appended to a pattern indicates that it must match at the end **
** of a line. **
** m...y A period matches any character except new-line : "m...y" matches any five **
** letter string starting with m and ending with y. **
** [xyz] A sequence inside the square brackets matches any character in the sequence **
** but no others. If the first character in the string is a ^, it matches any **
** character that is not in the string. For example, "[xyz]" matches "xx" **
** and "zyx", while "[^xyz]" matches "abc" but not "axb". **
** [a-z] Ranges within a standard ASCII order are indicated with a hyphen. Note that **
** [a-z] matches any alphabetic while [z-a] never matches. **
** :n A colon followed by a n matches any alphanumeric. **
** :v A colon followed by a v matches any character allowed in a variable name, **
** i.e. lowercase letter, digit or underscore. **
** \\$ A backslash before an otherwise special character matches it as a literal **
** character, e.g. "\\$" matches a dollar sign. To recognize a backslash itself **
** use \\\\. **
** @ two regular expressions separated by @ match either a match for the first or **
** a match for the second. @ is not allowed to be followed directly by *,+ or -. **
** **
** The concatenation of regular expressions is of course a regular expression. **
** **
*********************************************************************************************/
{
register CHAR *p_ptr; /* Current pointer in pbuf */
register CHAR c; /* Current character. */
CHAR *lp_ptr; /* Last pattern pointer. */
CHAR *save_ptr; /* Save end of pattern. */
CHAR *s_ptr; /* Source string pointer. */
CHAR bar_flg; /* is BAR if '@' is in the */
/* pattern string, 0 other- */
/* wise. */
CHAR **save3_pptr; /* *save3_pptr points to */
/* the last character in */
/* pbuf[] if it has been */
/* modified by comp_class().*/
CHAR *anchor_ptr; /* serves just as a defined location */
/* in memory. */
/*-------- Initialize variables -----------------------------------------------*/
bar_flg = 0; /* set bar_flg to "no '@'" */
s_ptr = source_ptr; /* Beginning of the keyword to compile */
p_ptr = pbuf; /* point at the first place of the array */
c = *source_ptr; /* read first character */
lp_ptr = NULL;
save_ptr = NULL;
save3_pptr = &anchor_ptr; /* initialize save3_pptr to a defined value. */
*save3_pptr = NULL;
p_ptr++; /* move pattern pointer one place forward*/
/* because pbuf[0] will contain bar_flg. */
/* printf(" Pattern = \"%s\"\n", s_ptr); */ /* Debugging code */
/*-------- Read the source keyword and compile it -----------------------------*/
while ( c NEQ '\0' ) /* while all char of pattern are not examined */
{
s_ptr++;
/*----- STAR, PLUS and MINUS are special ---------------------------------*/
/*----- (they indicate a number of occurences to match ) -----------------*/
if ((c EQ '*') OR (c EQ '+') OR (c EQ '-'))
{
store(ENDPAT,pbuf,p_ptr); /* Store ENDPAT to reserve a place */
p_ptr++; /* for STAR, PLUS or MINUS flag */
store(ENDPAT,pbuf,p_ptr); /* Store ENDPAT at the end of the pattern */
p_ptr++;
save_ptr = p_ptr; /* Save pattern end */
p_ptr++;
while (p_ptr > lp_ptr) /* Move pattern down one byte */
{ /* until the beginning of pattern */
*p_ptr = p_ptr[-1]; /* lp_ptr MUST NOT BE NULL !!! */
p_ptr--;
}
if (c EQ '*') /* to store there the appropriate flag */
{
*p_ptr = STAR; /* zero or more occurences */
}
else if (c EQ '-')
{
*p_ptr = MINUS; /* one or zero occurence */
}
else
{
*p_ptr = PLUS; /* one or more occurence */
}
p_ptr = save_ptr; /* Then restore pattern end */
c = *s_ptr;
continue; /* go back to while loop */
}
/*----- Other than star, plus or minus -----------------------------------*/
/*----- ( character or class of character to match ) ----------------------*/
lp_ptr = p_ptr; /* Remember start of the pattern */
switch (c) /* current char of the regular expression */
{
case '^': /* Beginning of a line */
store(BOL,pbuf,p_ptr);
p_ptr++;
break;
case '@': /* expression separator*/
bar_flg = BAR; /* now bar_flg != 0 */
store(BAR,pbuf,p_ptr);
p_ptr++;
break;
case '$': /* End of a line */
store(EOL,pbuf,p_ptr);
p_ptr++;
break;
case '.': /* Any character except new-line */
store(ANY,pbuf,p_ptr);
p_ptr++;
break;
case '[': /* Compile a whole string */
/*---- call comp_class() to compile it ------------------------------*/
s_ptr=comp_class(source_ptr,s_ptr,pbuf,p_ptr,save3_pptr);
p_ptr = *save3_pptr; /* end of compiled class in pattern template */
*save3_pptr = NULL;
break;
case ':': /* Class of characters */
if ( *s_ptr NEQ '\0' )
{
c = *s_ptr; /* read next character from pattern */
s_ptr++;
switch(tolower(c)) /* nature of the class */
{
case 'n': /* any alphanumeric */
store(NALPHA,pbuf,p_ptr);
p_ptr++;
break;
case 'v': /* any char of a var name */
store(VAR,pbuf,p_ptr);
p_ptr++;
break;
default:
printf("Cannot compile %s after ':'.\n", source_ptr);
exit(1);
break; /* (a badpat ends the program) */
}
break;
}
else
{
printf("\nBadpat after : in %s \n",source_ptr);
exit(1); /* (a badpat ends the program) */
}
case '\\': /* Symbol as regular character */
if ( *s_ptr NEQ '\0' )
{
c = *s_ptr; /* get symbol */
s_ptr++;
store(ACHAR,pbuf,p_ptr); /* store it as a regular char */
p_ptr++; /* you need two buffer places:*/
store(c,pbuf,p_ptr); /* one for ACHAR and one for */
p_ptr++; /* the character itself. */
}
break;
default : /* Single regular character */
store(ACHAR,pbuf,p_ptr);
p_ptr++;
store(c,pbuf,p_ptr);
p_ptr++;
break;
}
c = *s_ptr;
} /* end of while loop */
store(ENDPAT,pbuf,p_ptr);
p_ptr++;
store(0,pbuf,p_ptr); /* Terminate pattern string with 0 because ENDPAT */
p_ptr++; /* appears possibly several times in the pattern */
pbuf[0] = bar_flg; /* Indicate whether '@' has appeared or not. */
/* for (lp_ptr = pbuf; lp_ptr < p_ptr;) */ /* debugging code */
/* {
c = *lp_ptr;
lp_ptr++;
if ( c < ' ')
printf(" \\%ld ", c);
else
printf(" %c ", c);
}
printf("\n");*/
}
/*-------------- Store in pbuf[] ----------------------------------------------*/
void store(CHAR op, CHAR pbuf[PMAX], CHAR *p_ptr)
{
if ( p_ptr >= &pbuf[PMAX] ) /* check if there is place in pbuf[] */
{
printf("\nPattern is too complex to be compiled \n");
exit(1); /* (a too complex pattern ends the program) */
}
*p_ptr = op; /* store op in pbuf[] at p_ptr */
}
CHAR *comp_class( CHAR *source_ptr, CHAR *cl_st_ptr, CHAR pbuf[], CHAR *p_ptr, CHAR **save3_pptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : comp_class **
** VERSION : 001 **
** LONG_NAME : compile class found within [] **
** **
** **
** SPECIFICATION : This program is based on grep.c by David N. Smith **
** program of public domain CUG152.08. **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : comp_class compiles a class found in source[] **
** starting at cl_st_ptr in pbuf[] starting at p_ptr. **
** **
** REMARKS : **
** **
** FUNCTIONS : store(), exit(), printf(), return() **
** **
** GLOBALS : *save3_pptr : after comp_class(), will point to **
** end of class in pattern template **
** **
** PARAMETERS : source : points at the beginning of the regular **
** pattern, only used to print it if there **
** is a problem in it. **
** cl_st_ptr : points to the beginning of the class **
** in the regular expression. **
** pbuf : contains the pattern template **
** p_ptr : current position in pbuf given by compile()**
** before compiling the class itself **
** **
** PRECONDITIONS : the class in the pattern must be written as a **
** regular expression. **
** **
** POSTCONDITIONS : the class (or negative class) is stored in pbuf **
** as a string beginning with CLASS (or NCLASS), then **
** the size of the class (i) and the class itself : **
** a succession of regular characters and/or range **
** patterns, ie RANGE, followed by the two limit **
** characters : for example the result for **
** "[ad-ftr]" would be : CLASS 6 a RANGE d f t r **
** *save3_pptr points at the end of the class in the **
** pattern template. **
** **
** **
***C*F*E****************************************************************/
{
register CHAR *s_ptr; /* source pointer */
register CHAR c; /* current character */
CHAR *beg_ptr; /* beginning of the pattern within [] */
CHAR temp; /* temporaire */
LONG i; /* size of class */
/*-------- Initialize variables ---------------------------------------------*/
s_ptr = cl_st_ptr; /* point to class start */
beg_ptr = p_ptr; /* point to the current pointer in pbuf */
i = 0; /* size of the class */
c = *s_ptr;
/*-------- Store CLASS or NCLASS --------------------------------------------*/
temp = CLASS;
if ( c EQ '^' ) /* if pattern [^.... ie negative class */
{
temp = NCLASS ;
s_ptr = s_ptr + 1; /* point to the first char oif the class itself */
}
store(temp,pbuf,p_ptr); /* store appropriate flag */
p_ptr++; /* (CLASS or NCLASS) */
beg_ptr = p_ptr; /* point to start of class */
store(0,pbuf,p_ptr); /* Byte count */
p_ptr++;
c = *s_ptr; /* read the first char of the class itself */
/*-------- Compile the class itself ------------------------------------------*/
while ((c NEQ '\0') AND (c NEQ ']')) /* while not end of the class */
{
s_ptr = s_ptr + 1;
if ( c EQ '\\') /* Store special quoted char as a normal char */
{
c = *s_ptr;
s_ptr++;
if (c EQ '\0') /* gotta get something */
{
/* message d'erreur */;
exit(1); /* (badpat ends program) */
}
else
{
store(c,pbuf,p_ptr);
p_ptr++;
}
}
else if ( (c EQ '-') AND ((p_ptr - beg_ptr)> 1)
AND ( *s_ptr NEQ ']' ) AND ( *s_ptr NEQ '\0'))
{
c = p_ptr[-1]; /* Range start */
p_ptr[-1] = RANGE; /* Range signal */
store(c,pbuf, p_ptr); /* Re-store start */
p_ptr++;
c = *s_ptr; /* Get end char and */
s_ptr++;
store(c,pbuf,p_ptr); /* store it */
p_ptr++;
}
else /* Normal char */
{
store(c,pbuf,p_ptr); /* store it */
p_ptr++;
}
c = *s_ptr; /* Read next char */
}
s_ptr++;
i = p_ptr - beg_ptr; /* size of the class */
if (( c NEQ ']' ) OR (i >= 256) OR (i EQ 0))
{
printf("Bad class in the pattern : %s\n",source_ptr);
exit(1); /* (badpat ends program) */
}
*beg_ptr = (CHAR)i; /* store size of the class */
*save3_pptr = p_ptr; /* end of class in pbuf[] */
return(s_ptr); /* return a pointer to the next char to examine */
}
CHAR *part_match(CHAR *start_ptr, CHAR pattern[], LONG *l_ptr, CHAR **save2_pptr, CHAR mode)
/**C*F*******************************************************************
** **
** SRC-MODULE : part_match **
** VERSION : 001 **
** LONG_NAME : partial match **
** **
** **
** SPECIFICATION : This program is based on grep.c by David N. Smith **
** public domain CUG152.08 **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : part_match() tries to find a match of the pattern **
** starting exactly at start, skipping comments and **
** quoted text, and saving the current line in *line. **
** The end of match will be returned, NULL if none. **
** **
** REMARKS : - **
** **
** FUNCTIONS : return(), part_match(), exit(), printf() **
** **
** GLOBALS : *save2_pptr : points eventually to end of text **
** skipped by part_match() ie text to **
** skip for find_keyword() **
** **
** PARAMETERS : start_ptr : place where the match should start **
** pattern : points to beginning of pattern template **
** to match **
** l_ptr : contains the current line. As a pointer, **
** it keeps this value even after return. **
** mode: 0 --> it is assumed that the pattern in **
** pattern[] starts in location 0. **
** 1 --> pattern start in location 1. Location **
** zero is used by bar_flag. (See also **
** compile()). **
** **
** PRECONDITIONS : the comments and quoted text must be correct **
** ( braces_etc succeeded ) **
** **
** POSTCONDITIONS : returns the end of match found, NULL if none, and **
** saves in *save2_pptr the end of the last text **
** skipped over (NULL if none). **
** **
** **
***C*F*E****************************************************************/
{
register CHAR *p_ptr; /* current pattern pointer */
register CHAR *s_ptr; /* current source pointer */
CHAR c; /* current character */
LONG op; /* pattern operation */
CHAR *end_ptr; /* end for STAR and MINUS match */
CHAR *beg_ptr; /* start for STAR match */
LONG n; /* class counter */
CHAR *truc_ptr; /* save end of skipped text in */
/* order to avoid going through */
/* it more times than necessary */
CHAR *save_ptr;
CHAR match_flg; /* 1 on match, 0 if no match. */
CHAR bar_flg; /* >0 if BAR in pattern, 0 other-*/
/* wise. */
CHAR **help_pptr;
LONG line;
/*-------- Initialize variables ---------------------------------------------- */
s_ptr = start_ptr ; /* start of the search in source_file[] */
p_ptr = pattern ; /* start of the partial pattern to match */
help_pptr = save2_pptr;
line = *l_ptr;
bar_flg = 0; /* set bar_flg to "no BAR". */
if (mode EQ 0)
{
op = *p_ptr; /* points to first pattern character */
}
else
{
bar_flg = *p_ptr; /* bar_flg indicates presence of BAR. */
p_ptr++; /* switch to pattern[1]. */
op = *p_ptr; /* points to first pattern character */
}
n = 0; /* empty class */
c = 'a'; /* dummy value */
end_ptr = NULL;
beg_ptr = NULL;
truc_ptr = NULL;
match_flg = 1; /* set flag to "match" (no early return) */
/*------------- ---------------------- */
while ((op NEQ ENDPAT) AND (match_flg EQ 1) AND (op NEQ BAR))
{ /* while end of pattern temp- */
/* late not reached and there */
/* is still a match. */
/*-------- Skip over comment -------------------------------------------- */
if ((*s_ptr EQ '/') AND (*(s_ptr + 1) EQ '*'))
{
do /* go through it */
{
s_ptr++;
if ( *s_ptr EQ '\0' ) /* eventually incrementing n_line */
(*l_ptr)++;
}while ((*(s_ptr -1) NEQ '*') OR ( *s_ptr NEQ '/')); /* 'til its end */
*save2_pptr = s_ptr; /* save end of comment */
s_ptr++;
continue; /* (go back to while loop) */
}
/*-------- Skip over quoted text ---------------------------------------- */
/*------ ('"' is no start and \" is no end of quoted text )-------------- */
if ( (*s_ptr EQ '"') AND ((*(s_ptr-1) NEQ '\'') OR (*(s_ptr +1) NEQ '\'')) )
{
do /* go through it */
{
s_ptr++;
if (*s_ptr EQ '\0') /* incrementing eventually n_line */
(*l_ptr)++;
} while ((*s_ptr NEQ '"') OR (*(s_ptr-1) EQ '\\'));
*save2_pptr = s_ptr; /* save end of quoted text */
s_ptr++;
continue; /* (go back to while loop) */
}
/*-------- Examine pattern and source file ------------------------------ */
p_ptr++; /* point to next pattern symbol */
switch(op) /* current pattern operation */
{
case ACHAR: /* a character */
c = *s_ptr ;
s_ptr++;
if ( c NEQ *p_ptr )
{
match_flg = 0;
}
else
{
p_ptr++; /* one location further because ACHAR */
} /* needs two buffer places. */
break;
case BOL: /* beginning of a line */
if ( *(s_ptr - 1) NEQ '\0' )
match_flg = 0;
break;
case EOL: /* end of a line */
if ( *s_ptr NEQ '\0' )
match_flg = 0;
break;
case ANY: /* any character */
c = *s_ptr ;
s_ptr++;
if ( c EQ '\0' )
match_flg = 0;
break;
case NALPHA: /* any alphanumeric */
c = (CHAR)tolower( *s_ptr );
s_ptr++;
if ((c >= 'a') AND ( c <= 'z' ))
break;
else if (( c < '0' ) OR ( c > '9'))
match_flg = 0;
break;
case VAR: /* any char of a var name, i.e.*/
c = *s_ptr; /* alphanumeric or underscore */
s_ptr++;
if ( (c NEQ '_') AND ((c <'a') OR (c >'z')) AND ((c <'0') OR (c >'9')) )
match_flg = 0;
break;
case CLASS: /* any member of the following class */
case NCLASS: /* any nonmember of the following class */
c = *s_ptr;
if ( *s_ptr NEQ '\0') /* read next char if line is not finished */
s_ptr++;
n = ( *p_ptr); /* size of the class */
p_ptr++; /* first char of the class itself */
do /* Explore the class */
{
if ( *p_ptr EQ RANGE ) /* If range of char in the pattern */
{
p_ptr = p_ptr + 3; /* points after its limits */
n = n - 2; /* limits = two characters read */
if ((c >= p_ptr[-2] ) AND (c <= p_ptr[-1] )) /* got a match ? */
break;
}
else /* If the char in the pattern isn`t in a range */
{
if (c EQ *p_ptr) /* got a match ? */
{
p_ptr++;
break;
}
p_ptr++;
}
n = n - 1;
} while ( n > 1 ); /* class non fully examined */
if (((op EQ CLASS) AND (n <= 1)) OR ((op EQ NCLASS) AND (n > 1)))
{
match_flg = 0;
}
else if (op EQ CLASS) /* points in the pattern after the class */
{ /*(already done by a sucessfull nonclass)*/
p_ptr = p_ptr + n - 2;
}
break;
/*-----MINUS, PLUS and STAR require recursive programming by calling-----------*/
/*-----part_match() itself.----------------------------------------------------*/
case MINUS: /* Zero or one occurence */
end_ptr = part_match(s_ptr,p_ptr,l_ptr,save2_pptr,0); /* look for a match */
while ( *p_ptr NEQ ENDPAT)
p_ptr++; /* skip over pattern */
if (end_ptr NEQ NULL ) /* got a match ? */
s_ptr = end_ptr; /* yes, update string */
break; /* always succeeds */
case PLUS: /* One or more... */
s_ptr = part_match(s_ptr,p_ptr,l_ptr,save2_pptr,0);
if (s_ptr EQ NULL)
{
match_flg = 0; /* gotta have a match */
break;
}
/* the absence of break at the end of this case PLUS is deliberate, as */
/* one or more occurence is the same as one followed by zero or more ! */
case STAR: /* Zero or more... */
beg_ptr = s_ptr; /* remember line start */
save_ptr = *save2_pptr;
end_ptr = part_match(s_ptr,p_ptr,l_ptr,save2_pptr,0); /* look for match */
/*---- First eliminate all the char defined by the STAR pattern -----
---- by scanning along source_file[] current line and calling -----
---- part_match() until a mismatch is found. Then try to match ----
---- the rest of the template against the rest of text string. ----
---- If part_match() fails to match the tail, go backwards through
---- the characters just processed, while trying to match the -----
---- trailing string against the rest of the pattern template. ----
---- This is necessary because the character following the 'STAR'--
---- could have been included in the 'STAR' pattern itself. -------
---- ( For example : [a-d]*b : b will be absorbed by the first ----
---- scan, it is necessary to go backwards eg in aaaaabccccc ) ----*/
/*------------ get longest match ------------------------------------*/
while ((end_ptr NEQ NULL) AND (*end_ptr NEQ '\0'))
{
*save2_pptr = NULL; /* ???????????? */
s_ptr = end_ptr;
end_ptr = part_match(s_ptr,p_ptr,l_ptr,save2_pptr,0); /* next match */
}
if (*save2_pptr NEQ NULL ) /* If text skipped, */
{
s_ptr = *save2_pptr + 1; /* points after it */
}
/*------------ skip over pattern ------------------------------------*/
while ( *(p_ptr - 1) NEQ ENDPAT)
{
p_ptr++;
}
/*------------ try to match rest ------------------------------------*/
while (( s_ptr >= beg_ptr ) AND ( *s_ptr NEQ '\0'))
{
end_ptr = part_match(s_ptr,p_ptr,l_ptr,save2_pptr,0); /* look for match */
if ( end_ptr NEQ NULL ) /* if match found */
return(end_ptr);
if ((*save2_pptr NEQ NULL) AND (s_ptr NEQ beg_ptr) AND (*save2_pptr NEQ truc_ptr) )
{
s_ptr = *save2_pptr + 1;
}
s_ptr--; /* nope,go backwards */
if (s_ptr <= beg_ptr) /* (if beginning of star */
continue; /* match reached, go back to while loop) */
/*-------------- skipping over comment ----------------------------*/
if (( *s_ptr EQ '/') AND ( *(s_ptr - 1) EQ '*'))
{
truc_ptr = s_ptr; /* save end of comment */
do
{
s_ptr--; /* go backwards one char */
if (*s_ptr EQ '\0') /* ev. decrementing line number */
(*l_ptr)-- ;
}while ((*s_ptr NEQ '*' ) OR ( *(s_ptr - 1) NEQ '/'));
s_ptr = s_ptr - 2;
continue; /* go back to while loop */
}
/*--------------- skipping over quoted text -----------------------*/
if (( *s_ptr EQ '"')
AND (( *(s_ptr-1) NEQ '\'') OR ( *(s_ptr+1) NEQ '\'')) )
{
truc_ptr = s_ptr; /* save end of quoted text */
do
{
s_ptr--; /* go one char back */
if ( *s_ptr EQ '\0') /* ev. decrementing line counter */
(*l_ptr)--;
}while (( *s_ptr NEQ '"') OR (*(s_ptr -1) EQ '\\'));
s_ptr = s_ptr - 2;
}
} /* end of while loop */
if ((*save2_pptr EQ NULL) AND (save_ptr NEQ NULL))
*save2_pptr = save_ptr;
match_flg = 0; /* nothing else worked */
break;
default:
printf("Bad op code %ld at place %ld\n",op,(p_ptr - 1 - pattern));
exit(1); /* (badpat ends the program) */
break;
}/* End of switch */
op = *p_ptr; /* next operation of the pattern */
if ((match_flg EQ 0) AND (bar_flg > 0)) /* if there was no match and */
{ /* there is BAR in pattern. */
while ((op NEQ 0) AND (op NEQ BAR)) /* then search for BAR to */
{ /* find alternative pattern*/
p_ptr++; /* to match. */
op = *p_ptr;
}
if (op EQ BAR) /* if there is an alternative pattern */
{ /* give part_match() another chance. */
match_flg = 1; /* if op EQ ENDPAT, however, match_flg*/
s_ptr = start_ptr; /* will remain 0 and stop the while */
n = 0; /* loop. Reinitialize now! */
end_ptr = NULL;
beg_ptr = NULL;
truc_ptr = NULL;
save2_pptr = help_pptr;
*l_ptr = line;
p_ptr++;
op = *p_ptr; /* first pattern character of alter- */
} /* native pattern. */
}
}/* End of while */
/*-----Finally check whether there has been any match-------------------------*/
if (match_flg EQ 1)
{
return(s_ptr); /* return pointer to end of match found in source_file[].*/
}
else
{
return(NULL);
}
}
void forbidden_keyword(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : forbidden_keyword **
** VERSION : 001 **
** LONG_NAME : forbidden_keyword **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : forbidden_keyword() looks for expressions that are **
** not allowed in source_file[]. It calls **
** find_keyword() for each pattern already compiled **
** and prints a warning in fout_ptr for each match **
** found. **
** **
** REMARKS : the explicit list of forbidden keywords is in **
** *false_ptr[]. **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file[] **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf[PMAX]; /* compiled pattern */
T_LOCA loca_1; /* current location of keyword */
LONG i; /* universal counter */
CHAR *st_ptr; /* start of the search */
LONG ligne; /* start of the search */
/*---------- Initialize variables ---------------------------------------------*/
CHAR *pattern_ptr[] = /* patterns to compile (see compile() ) */
{ /* to find the non-allowed expressions */
"&&","||","==","!=",
"extern","static",
" long ","^long ", /* type name shall be preceeded by */
" short ","^short ", /* space or at the beginning of a */
" char ","^char ", /* line */
" int ","^int ",
" \\**l[ ;]", /* l or *l or *l; or l; */
"goto ",
"=\\-","\\-\\-\\-",
"\\+=","\\*=",
"\\-=","/=",
"\\*( *\\*(",
/* "\\*\\*", */
" _:n",
":n__+:n",
"\t",
"the_end"
};
CHAR *false_ptr[] = /* explicit non-allowed expressions */
{ /* used in */
"&&","||","==","!=", /* warning messages */
"extern","static",
"unsigned or (signed) long","unsigned or (signed) long",
"unsigned or (signed) short","unsigned or (signed) short",
"unsigned or (signed) char","unsigned or (signed) char",
"int","int",
"l (easily confused with 1)",
"goto",
"=-","---",
"+=","*=",
"-=","/=",
"*(*(pointer_name... ))",
/* "pointer to pointer", */
"_name",
"variable__name",
"tabulation"
};
CHAR *right_ptr[] = /* explicit correct expressions */
{ /* used in */
"AND","OR","EQ","NEQ", /* warning messages */
"IMPORT","LOCAL",
"ULONG or LONG","ULONG or LONG",
"USHORT or SHORT","USHORT or SHORT",
"UCHAR or CHAR","UCHAR or CHAR",
"either BITFIELD if unsigned or SHORT or LONG if signed","either BITFIELD if unsigned or SHORT or LONG if signed",
"any other variable name",
"statements like return, break and continue",
" = - ( "," parentheses or even better several statements ",
"the non-shorthand notation","the non-shortand notation",
"an explicit notation","an explicit notation",
"index notation for ease of readability",
/* "index notation for ease of readability", */
"a name that doesn't start with an underscore",
"a name that doesn't contain a double underscore",
"spaces"
};
ligne = 1;
st_ptr = source_file; /* first line */
/*---------- Look for each non correct expression -----------------------------*/
for ( i=0; strncmp(pattern_ptr[i],"the_end",7) NEQ 0 ; i++)
{
/*--- compile pattern of non-allowed expression ---------------------------*/
/*--- and store it in pbuf[]-----------------------------------------------*/
compile(pattern_ptr[i],pbuf);
/*--- try to find not allowed keyword -------------------------------------*/
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf); /* first match */
while ((loca_1.line_no)> 0) /* while match found */
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : %s shouldn't be used,", loca_1.line_no, false_ptr[i]);
fprintf(fout_ptr," please use %s instead.",right_ptr[i]);
st_ptr = loca_1.end_ptr;
ligne = loca_1.line_no;
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf); /* next match */
}
st_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void right_place(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : right_place **
** VERSION : 001 **
** LONG_NAME : right place **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : right_place looks for expressions that contain **
** keywords at a wrong place in source_file[] and **
** prints a warning in fout_ptr for each match found. **
** **
** REMARKS : explicit keywords are in false_ptr[] and their **
** corresponding right places are in right_ptr[]. **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf[PMAX]; /* compiled pattern */
CHAR pbufbis[PMAX];
LONG ligne; /* ligne the search begins at */
T_LOCA loca_1; /* current location of keyword */
T_LOCA loca_2;
LONG i; /* universal counter */
CHAR *st_ptr; /* place to start the search */
/*---------- Initialize variables ---------------------------------------------*/
CHAR *pattern_ptr[] = /* patterns to look for */
{ /* once compiled in pbuf */
"[^ ] *typedef",
"[^ ] *EXPORT",
"[^ ] *IMPORT",
"[^ ] *LOCAL",
"[^ ] *auto",
"[^ ] *register",
"[^ ] *volatile",
"[^ \t'] *{", /* anything except blank, tab and ' is forbidden. */
"{ *[^ \t']",
"[^ \t'] *}",
"} *[^ \t';]",
"; *[¡-²!-~]", /* ASCII class : anything but space */
"the_end"
};
CHAR *pat_bis[] = /* Exception patterns */
{
" *enum *",
" *enum *",
" *enum *",
" *while *",
" *for *("
};
CHAR *false_ptr[] = /* explicit keyword at a wrong place */
{ /* used in warning message */
"typedef",
"EXPORT",
"IMPORT",
"LOCAL",
"auto",
"register",
"volatile",
"{",
"{",
"}",
"}",
";"
};
CHAR *right_ptr[] = /* explicit right place of each keyword */
{ /* used in warnings */
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"at the beginning of the declaration statement",
"in a separate line",
"in a separate line",
"in a separate line",
"in a separate line",
"at the end of the line. There should be no more than one executable statement in a single line"
};
ligne = 1;
st_ptr = source_file; /* first line */
i = 0;
/*---------- Look for each expression at a wrong place ------------------------*/
for ( i=0; strncmp(pattern_ptr[i],"the_end",7) NEQ 0 ; i++ )
{
/*----- compile each pattern with the expression at a wrong place --------*/
compile(pattern_ptr[i],pbuf);
if (i>6)
{
compile(pat_bis[i-7],pbufbis);
}
/*----- try to find keyword at a wrong place -----------------------------*/
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf);
while ((loca_1.line_no)> 0) /* while match found */
{
if (i>6) /* if there are exceptions */
{
if (loca_1.line_no > 1) /* if match is not in first line. */
{
while ( *(st_ptr-1) NEQ '\0' ) /* go back to start of line. */
{
st_ptr--;
}
}
else /* if match in first line go back to start */
{ /* of file (There's no \0 at the beginning!).*/
st_ptr = source_file;
}
do
{
loca_2 = find_keyword(st_ptr, ligne, nb_line, pbufbis);
st_ptr = loca_2.end_ptr;
ligne = loca_2.line_no;
}while( (loca_2.line_no NEQ 0) AND (loca_2.line_no < loca_1.line_no));
}
if ((i<=6) OR ((i>6) AND (loca_2.line_no NEQ loca_1.line_no)) )
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : the symbol %s ", loca_1.line_no, false_ptr[i]);
fprintf(fout_ptr,"should stand %s.", right_ptr[i]);
}
st_ptr = loca_1.end_ptr;
ligne = loca_1.line_no;
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf); /* next match */
}
st_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void user_type_name(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : user_type_name **
** VERSION : 001 **
** LONG_NAME : user type name **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : user_type_name looks for declaration of user type **
** that are not followed by a correct name in **
** source_file[] and prints a warning in fout_ptr **
** for each match found. **
** **
** REMARKS : typedef is special : user_type_name looks first **
** for a } and only after it for a correct name. **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file : **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf1[PMAX]; /* compiled type name */
CHAR pbuf2[PMAX]; /* compiled begin of var name */
CHAR pbuf3[PMAX]; /* ...for typedef */
T_LOCA loca_1; /* current loca of type name */
T_LOCA loca_2; /* current loca of correct name*/
LONG i; /* universal counter */
CHAR *st_ptr; /* start of the search */
LONG ligne; /* start of the search */
LONG end_line; /* end of the search */
/*---------- Initialize variables ---------------------------------------------*/
CHAR *pattern_ptr[] = /* patterns to compile */
{ /* in pbuf1 (type name) */
"^ *struct " ,"S_", /* in pbuf2 (start of correct var name) */
"^ *enum " ,"E_",
"^ *union " ,"U_",
"^ *const " ,"C_",
"^ *typedef " ,"}" , "T_",
"the_end"
};
ligne = 1;
st_ptr = source_file; /* first line */
end_line = nb_line;
/*---------- Look for each non correct user type or constant name -------------*/
for ( i=0; strncmp(pattern_ptr[i],"the_end",7) NEQ 0 ; i = i+2)
{
/*---- compile patterns of type name and start of correct var name -------*/
compile(pattern_ptr[i], pbuf1);
compile(pattern_ptr[i+1],pbuf2);
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf1); /* loc of type name */
if (i EQ 8) /* typedef : 3 patterns */
{ /* to compile */
compile(pattern_ptr[i+2],pbuf3);
i++;
}
/*------ Look for each declaration of the same type ----------------------*/
while ((loca_1.line_no)> 0) /* while type name found */
{
if ((loca_1.line_no < nb_line -1 ) AND (i NEQ 9)) /* for speed */
{
end_line = loca_1.line_no + 1;
}
/*---- try to find a name beginning as expected ------------------------*/
loca_2 = find_keyword(loca_1.end_ptr, loca_1.line_no, end_line, pbuf2);
if ( i EQ 9 ) /* typedef : look for }T_ */
{
loca_1 = loca_2;
loca_2 = find_keyword(loca_1.end_ptr,loca_1.line_no, end_line, pbuf3);
}
/*---- Warning if no correct name found in the declaration -------------*/
if ( loca_1.line_no NEQ loca_2.line_no )
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : the name of this identifier or constant is wrong,", loca_1.line_no);
fprintf(fout_ptr," it should begin with %s .\n",pattern_ptr[i+1]);
}
st_ptr = loca_1.end_ptr;
ligne = loca_1.line_no;
end_line = nb_line;
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf1); /* next match */
}
st_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void ptr_name(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : ptr_name **
** VERSION : 001 **
** LONG_NAME : pointer name **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : ptr_name() looks in source_file[] for declarations **
** of pointers and then looks for a declaration of **
** correct name (ending with _ptr). If none is found **
** in the same line, it prints a warning in fout_ptr. **
** **
** REMARKS : names of pointers to a type that has been defined **
** in the define part are not checked. **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf1[PMAX]; /* compiled patt: pointer */
CHAR pbuf2[PMAX]; /* compiled patt: pointer_ptr */
T_LOCA loca_1; /* location of a pointer */
T_LOCA loca_2; /* location of a pointer_ptr */
LONG i; /* universal counter */
CHAR *st_ptr; /* start of the search */
LONG ligne; /* start of the search */
LONG end_line; /* end of the search */
/*---------- Initialize variables ---------------------------------------------*/
CHAR *false_ptr[] = /* patterns to compile in pbuf1 and pbuf2 */
{
"FILE *\\*:v+ *[;,)]" ,"FILE *\\*:v+_ptr *[;,)]",
"CHAR *\\*:v+ *[;,)]" ,"CHAR *\\*:v+_ptr *[;,)]", /* matches CHAR and UCHAR */
"LONG *\\*:v+ *[;,)]" ,"LONG *\\*:v+_ptr *[;,)]", /* matches LONG and ULONG */
"SHORT +\\*:v+ *[;,)]" ,"SHORT *\\*:v+_ptr *[;,)]", /* matches SHORT and USHORT */
"BITFIELD +\\*:v+ *[;,)]","BITFIELD +\\*:v+_ptr *[;,)]",
"S_[A-Z0-9_]+ +\\*:v+ *[;,)]" ,"S_[A-Z0-9_]+ +\\*:v+_ptr *[;,)]",
"T_[A-Z0-9_]+ +\\*:v+ *[;,)]" ,"T_[A-Z0-9_]+ +\\*:v+_ptr *[;,)]",
"U_[A-Z0-9_]+ +\\*:v+ *[;,)]" ,"U_[A-Z0-9_]+ +\\*:v+_ptr *[;,)]",
"E_[A-Z0-9_]+ +\\*:v+ *[;,)]" ,"E_[A-Z0-9_]+ +\\*:v+_ptr *[;,)]",
" (\\*:v+) *( *) *[;,)]" ," (\\*:v+_ptr) *( *) *[;,)]", /* ptr to fction */
"FILE *\\*\\*:v+ *[;,)]" ,"FILE *\\*\\*:v+_pptr *[;,)]",
"CHAR *\\*\\*:v+ *[;,)]" ,"CHAR *\\*\\*:v+_pptr *[;,)]", /* matches CHAR and UCHAR */
"LONG *\\*\\*:v+ *[;,)]" ,"LONG *\\*\\*:v+_pptr *[;,)]", /* matches LONG and ULONG */
"SHORT +\\*\\*:v+ *[;,)]" ,"SHORT *\\*\\*:v+_pptr *[;,)]", /* matches SHORT and USHORT */
"BITFIELD +\\*\\*:v+ *[;,)]","BITFIELD +\\*\\*:v+_pptr *[;,)]",
"S_[A-Z0-9_]+ +\\*\\*:v+ *[;,)]" ,"S_[A-Z0-9_]+ +\\*\\*:v+_pptr *[;,)]",
"T_[A-Z0-9_]+ +\\*\\*:v+ *[;,)]" ,"T_[A-Z0-9_]+ +\\*\\*:v+_pptr *[;,)]",
"U_[A-Z0-9_]+ +\\*\\*:v+ *[;,)]" ,"U_[A-Z0-9_]+ +\\*\\*:v+_pptr *[;,)]",
"E_[A-Z0-9_]+ +\\*\\*:v+ *[;,)]" ,"E_[A-Z0-9_]+ +\\*\\*:v+_pptr *[;,)]",
" (\\*\\*:v+) *( *) *[;,)]" ," (\\*\\*:v+_pptr) *( *) *[;,)]", /* ptr to fction */
"the_end"
};
ligne = 1;
st_ptr = source_file; /* first line */
/*---------- Look for each non correct expression -----------------------------*/
for ( i=0; strncmp(false_ptr[i],"the_end",7) NEQ 0 ; i = i+2)
{
/*----- compile each pattern coresponding to a pointer declaration -------*/
/*----- and look for a match ---------------------------------------------*/
compile(false_ptr[i],pbuf1);
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf1);
if (loca_1.line_no < (nb_line -1)) /* useful for speed */
end_line = loca_1.line_no +1;
else
end_line = nb_line;
/*---- compile each pattern of a declaration of pointer ending with _ptr --*/
/*---- and look for a match -----------------------------------------------*/
compile(false_ptr[i+1],pbuf2);
loca_2 = find_keyword(st_ptr, ligne, end_line, pbuf2);
while ((loca_1.line_no)> 0) /* while non examined ptr declaration are left */
{
if (loca_2.end_ptr NEQ loca_1.end_ptr)
{
/* fprintf(fout_ptr,"\nMATCH AT PATTERN NO. %4ld",i); */ /* Debug code */
fprintf(fout_ptr,"\nWARNING (line %4ld) : the name of this pointer is wrong,", loca_1.line_no);
if (i < 20)
{
fprintf(fout_ptr," it should end with _ptr.");
}
else
{
fprintf(fout_ptr," it should end with _pptr. As an alternative");
fprintf(fout_ptr," you could use index notation which most often enhances readability.\n");
}
}
st_ptr = loca_1.end_ptr;
ligne = loca_1.line_no;
/*------ next declaration of pointer ------------------------------------*/
loca_1 = find_keyword(st_ptr, ligne, nb_line, pbuf1);
if (loca_1.line_no < (nb_line -1)) /* useful for speed */
end_line = loca_1.line_no +1;
else
end_line = nb_line;
/*------ next declaration of pointer with name ending with _ptr ---------*/
loca_2 = find_keyword(st_ptr, ligne, end_line, pbuf2);
}
st_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void switch_stat(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : switch_stat **
** VERSION : 001 **
** LONG_NAME : switch statement **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : switch_stat looks for each switch statement in **
** source_file[] and looks for code between switch **
** and case or break and case. It prints a warning **
** in fout_ptr if there is code between switch and **
** first case or if there is no break before case. **
** **
** REMARKS : the last break is not checked **
** **
** FUNCTIONS : compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
/* compiled patterns : */
CHAR pswitch[PMAX]; /* switch */
CHAR pcase[PMAX]; /* case */
CHAR pbreak[PMAX]; /* break */
CHAR psth[PMAX]; /* anything but space and } */
T_LOCA l_switch; /* current location of switch */
T_LOCA l_break; /* current location of break */
T_LOCA l_case1; /* location of first case */
T_LOCA l_case2; /* location of second case */
T_LOCA l_between; /* current location of any */
/* unexpected character */
CHAR *start_ptr; /* start of the search */
LONG ligne; /* start of the search */
/*---------- Initialize variables ---------------------------------------------*/
ligne = 1;
start_ptr = source_file; /* first line */
compile(" switch *(.*)",pswitch);
compile(" case ",pcase);
compile(" break;",pbreak);
compile("[¡-ÿ!-z|-~]",psth); /* ASCII : anything but { and space */
/*---------- Look for each non correct expression -----------------------------*/
l_switch = find_keyword(start_ptr, ligne, nb_line, pswitch);
while ( l_switch.line_no > 1) /* while there is a switch stat to examine */
{
start_ptr = l_switch.end_ptr;
ligne = l_switch.line_no;
l_switch = find_keyword(start_ptr, ligne, nb_line, pswitch);
/*-------- check presence of code between switch and first case -----------*/
l_case1 = find_keyword(start_ptr, ligne, nb_line, pcase);
l_between = find_keyword(start_ptr, ligne, nb_line, psth);
if (l_between.line_no < l_case1.line_no)
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : there should be no ",l_between.line_no);
fprintf(fout_ptr,"program code between the switch statement and the first case label.");
}
/*-------- look for second case-block -------------------------------------*/
/*-------- (cases in two following lines belong to the same block) --------*/
l_case2 = find_keyword(l_case1.end_ptr, l_case1.line_no, nb_line, pcase);
while ((l_case2.line_no NEQ 0) AND ((l_case2.line_no - l_case1.line_no) <=1))
{
l_case1 = l_case2;
l_case2 = find_keyword(l_case1.end_ptr, l_case1.line_no, nb_line, pcase);
}
if (l_case2.line_no EQ 0) /* if none */
break; /* go back to while loop (examine next switch)*/
/*-------- examine each case-block before next switch ----------------------*/
while ((l_switch.line_no EQ 0 ) OR (l_switch.line_no > l_case2.line_no))
{
l_break = find_keyword(start_ptr, ligne, nb_line, pbreak);
/*------ look for a break just before the case(2) statement --------------*/
while ((l_break.line_no NEQ 0) AND (l_break.line_no < l_case2.line_no))
{
l_between = find_keyword(l_break.end_ptr, l_break.line_no, nb_line, psth);
if (l_between.line_no >= l_case2.line_no )
break;
l_break = find_keyword(l_break.end_ptr, l_break.line_no, nb_line, pbreak);
}
/*------ if break is missing ---------------------------------------------*/
if ((l_break.line_no EQ 0) OR (l_break.line_no > l_case2.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : there is no break before this case. ",l_case2.line_no);
fprintf(fout_ptr,"If the fall-through behaviour is deliberate, don't forget extensive comments !");
}
/*------ next case statement ---------------------------------------------*/
do
{
l_case1 = l_case2;
l_case2 = find_keyword(l_case1.end_ptr,l_case1.line_no,nb_line,pcase);
}while ((l_case2.line_no NEQ 0) AND ((l_case2.line_no - l_case1.line_no) <= 1));
if (l_case2.line_no EQ 0) /* (if no case left go back to first) */
break; /* (while loop ie examine next switch) */
}
}
}
void default_stat(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : default_stat **
** VERSION : 001 **
** LONG_NAME : default statement **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : default_stat() looks for a switch selection and **
** calls recurs() for each one found, which looks **
** for nested switch selection and works recursively **
** to find a default label in each selection. If none **
** is found, a warning is printed in output file. **
** **
** REMARKS : **
** **
** FUNCTIONS : compile(), find_keyword(), fprintf(), recurs(), **
** return() **
** **
** GLOBALS : source_file[] **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
T_LOCA l_end_tst; /* end of code checked by recurs() */
T_LOCA l_switch; /* position of current switch */
CHAR psw[PMAX]; /* pattern template : switch */
CHAR pdef[PMAX]; /* pattern template : default */
CHAR *start_ptr; /* start of search for switch */
LONG ligne; /* start of search for switch */
/*------- Initialize variables ----------------------------------------------*/
start_ptr = source_file;
ligne = 1;
compile(" switch *(",psw);
compile(" default[ :]",pdef);
l_switch = find_keyword(start_ptr,ligne,nb_line,psw);
/*------- Scan source_file[] for switch selection, calling recursive() ------*/
/*------- using recursion for nested switch selections ----------------------*/
while (l_switch.line_no NEQ 0) /* while non examined switch */
{
l_end_tst = recurs(l_switch,nb_line,psw,pdef,fout_ptr);
start_ptr = l_end_tst.end_ptr;
ligne = l_end_tst.line_no;
l_switch = find_keyword(start_ptr,ligne,nb_line,psw); /* next match */
}
}
/*-----------------------------------------------------------------------------*/
/*--------- Recursive checking function ---------------------------------------*/
/*-----------------------------------------------------------------------------*/
T_LOCA recurs(T_LOCA l_switch, LONG nb_line, CHAR psw[], CHAR pdef[], FILE *fout_ptr)
{
T_LOCA l_nxt_sw; /* location of next switch */
T_LOCA l_default; /* location of current default */
T_LOCA l_open; /* location of current { */
T_LOCA l_close; /* location of current } */
T_LOCA l_end_sw; /* end of current switch selection */
T_LOCA l_end_tst; /* end of last examined switch */
/* selection :returned by recurs() */
CHAR *start_ptr; /* start of the search */
LONG ligne; /* start of the search */
LONG count; /* counts braces */
CHAR popen[PMAX]; /* pattern template : opened brace */
CHAR pclose[PMAX]; /* pattern template : closed brace */
/*------ Initialize variables ----------------------------------------------*/
start_ptr = l_switch.end_ptr; /* start search after current switch */
ligne = l_switch.line_no;
l_nxt_sw = find_keyword(start_ptr,ligne,nb_line,psw); /* next switch */
l_default = find_keyword(start_ptr,ligne,nb_line,pdef); /* default */
count = 0; /* reset counter */
compile("{[^']",popen); /* no quoted brace */
compile("}[^']",pclose); /* no quoted brace */
/*----- find end of current switch statement -------------------------------*/
l_open = find_keyword(start_ptr,ligne,nb_line,popen); /* first { */
l_close = find_keyword(start_ptr,ligne,nb_line,pclose); /* first } */
do
{
while (( l_open.line_no < l_close.line_no ) AND (l_open.line_no NEQ 0))
{
count++;
start_ptr = l_open.end_ptr;
ligne = l_open.line_no;
l_open = find_keyword(start_ptr,ligne,nb_line,popen);
}
while (( l_close.line_no < l_open.line_no ) OR (l_open.line_no EQ 0))
{
count--;
if (count EQ 0) /* if end of switch selection found */
{
l_end_sw = l_close;
break;
}
start_ptr = l_close.end_ptr;
ligne = l_close.line_no;
l_close = find_keyword(start_ptr,ligne,nb_line,pclose);
}
}while (count NEQ 0);
/*----- if no switch and no default in current switch block ----------------*/
if ( ((l_nxt_sw.line_no EQ 0) OR (l_nxt_sw.line_no > l_end_sw.line_no ))
AND ((l_default.line_no EQ 0) OR (l_end_sw.line_no < l_default.line_no)) )
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : every switch selection must ", l_switch.line_no);
fprintf(fout_ptr,"exhibit a default label.");
return(l_end_sw);
}
/*----- if other switch to examine in current switch block ----------------*/
else if ((l_nxt_sw.line_no NEQ 0) AND ( l_nxt_sw.line_no < l_end_sw.line_no ))
{
/*--- examine all switches within the current switch block --------------*/
do
{
l_end_tst = recurs(l_nxt_sw,nb_line,psw,pdef,fout_ptr);
start_ptr = l_end_tst.end_ptr;
ligne = l_end_tst.line_no;
l_nxt_sw = find_keyword(start_ptr,ligne,nb_line,psw);
l_default = find_keyword(start_ptr,ligne,nb_line,pdef);
}while((l_nxt_sw.line_no < l_end_sw.line_no) AND (l_nxt_sw.line_no NEQ 0));
/*--- check presence of default for current switch block ----------------*/
if ((l_default.line_no EQ 0) OR (l_default.line_no > l_end_sw.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : every switch selection must ",l_switch.line_no);
fprintf(fout_ptr,"exhibit a default label. ");
}
}
/*---- examine next non nested switch selection ---------------------------*/
return(l_end_sw); /* return end of current switch selection */
}
void tst_loop(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : tst_loop **
** VERSION : 001 **
** LONG_NAME : test of loop **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : tst_loop() looks for implicit tests and assignments**
** in conditional statements and looks if a pointer **
** value is compared with 0 instead of NULL after **
** each loop in source_file[] and prints a **
** warning in fout_ptr if necessary. **
** **
** REMARKS : **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf_loop[PMAX]; /* loop pattern */
CHAR pbuf_conj[PMAX]; /* conjonction pattern */
CHAR pbuf_test[PMAX]; /* test pattern */
CHAR popen[PMAX]; /* patt ( */
CHAR pclose[PMAX]; /* patt ) */
T_LOCA loca_loop; /* current location of loop */
T_LOCA loca_conj; /* current location of conjonc */
T_LOCA loca_tst; /* current location of test */
T_LOCA l_open; /* location of opened brace */
T_LOCA l_close; /* location of closed brace */
T_LOCA l_end_tst; /* end of ctrl flow statement */
LONG i; /* universal counter */
LONG j; /* universal counter */
CHAR *start_ptr; /* place to start the search */
LONG ligne; /* line to start the search */
LONG end_line; /* line to end the search */
LONG nb_tst; /* nb of tests in control stat */
LONG nb_expl_tst; /* nb of explicit tests in the */
/* current control statement */
LONG count; /* counts braces to find end of*/
/* control flow statement */
LONG bip; /* flag used to find the exact */
/* end of brace */
/*---------- Initialize variables ---------------------------------------------*/
CHAR *loop_ptr[] = /* patterns to compile : loops if and while */
{
"[^d]if[ (]", /* neither endif nor ifndef or ifdef */
"while[ (]",
"the_end"
};
CHAR *pattern_conj[] = /* patterns to compile : conjonctions */
{ /* (there is one more test than conjonctions) */
"[ )]AND[ (]","[ )]AND$",
"[ )]OR[ (]","[) ]OR$",
"&&[ (]","&&$", /* conjonctions are followed by space or ( */
"||[ (]","||$", /* or at the end of a line */
"the_end"
};
CHAR *pattern_test[] = /* patterns to compile : explicit tests */
{
" N*EQ", /* EQ or NEQ */
"[!=]=", /* == or != */
"[^\\-][<>]=*", /* comparaison */
"the_end"
};
ligne = 1;
start_ptr = source_file; /* first line */
nb_tst = 1;
nb_expl_tst = 0;
count = 0; /* set all counters to zero */
bip = 0;
compile("([^']",popen); /* non quoted brace */
compile(")[^']",pclose); /* non quoted brace */
/*---------- Look for each loop with a bad test method ------------------------*/
for ( i=0; strncmp(loop_ptr[i],"the_end",7) NEQ 0 ; i++)
{
compile(loop_ptr[i],pbuf_loop);
loca_loop = find_keyword(start_ptr, ligne, nb_line, pbuf_loop);
while ((loca_loop.line_no)> 0) /* while loop not examined */
{
start_ptr = loca_loop.end_ptr;
if ( *(start_ptr-1) EQ '(') /* if brace included in the loop match */
start_ptr--; /* go back to examine it too */
ligne = loca_loop.line_no;
/*------ look for end of tests of the loop ----------------------------*/
l_open = find_keyword(start_ptr,ligne,nb_line,popen); /* first ( */
l_close = find_keyword(start_ptr,ligne,nb_line,pclose); /* first ) */
if ( (*l_close.end_ptr NEQ '\0') OR
((*l_close.end_ptr EQ '\0') AND (*(l_close.end_ptr-2) EQ ')') AND (l_close.end_ptr NEQ (start_ptr+1))) )
{
bip=0; /* bip is a flag used to know the exact end of the */
} /* brace examined : l_close points after the char */
else /* following the brace (bip=0) to check it is no */
{ /* quote but if the brace is at the end of the line*/
bip=1; /* it points to \0 (bip=1),ie just after the brace */
}
do /* go through braces until end of control flow statement found */
{
while (( l_open.end_ptr < l_close.end_ptr ) AND (l_open.line_no NEQ 0))
{
count++;
start_ptr = l_open.end_ptr;
if (*start_ptr NEQ '\0')
start_ptr--;
ligne = l_open.line_no;
l_open = find_keyword(start_ptr,ligne,nb_line,popen); /* next */
}
while (( l_close.end_ptr < l_open.end_ptr ) OR (l_open.line_no EQ 0))
{
count--;
if (count EQ 0) /* if end of test(s) found */
{
l_end_tst = l_close;
break;
}
if (bip EQ 1) /* start_ptr points just */
start_ptr = l_close.end_ptr; /* after the brace */
else /* examined */
start_ptr = l_close.end_ptr - 1;
ligne = l_close.line_no;
l_close = find_keyword(start_ptr,ligne,nb_line,pclose);
if ( (*l_close.end_ptr NEQ '\0') OR
((*l_close.end_ptr EQ '\0') AND (*(l_close.end_ptr-2) EQ ')') AND (l_close.end_ptr NEQ (start_ptr+1))) )
{
bip=0; /* match was two char long */
}
else
{
bip=1; /* match was one char long */
}
}
}while (count NEQ 0);
if (l_end_tst.line_no < nb_line) /* useful for speed */
end_line = l_end_tst.line_no +1;
else
end_line = nb_line;
/*------ look for conjunctions between tests of the loop --------------*/
for ( j=0 ; strncmp(pattern_conj[j],"the_end",7) NEQ 0 ; j++)
{
compile(pattern_conj[j],pbuf_conj);
start_ptr = loca_loop.end_ptr;
ligne = loca_loop.line_no;
loca_conj = find_keyword(start_ptr, ligne, end_line, pbuf_conj);
while ((loca_conj.line_no NEQ 0) AND (loca_conj.end_ptr < l_end_tst.end_ptr))
{
nb_tst++;
start_ptr = loca_conj.end_ptr;
ligne = loca_conj.line_no;
loca_conj = find_keyword(start_ptr, ligne, end_line, pbuf_conj);
}
}
/*------ look for explicit tests --------------------------------------*/
for ( j=0 ; strncmp(pattern_test[j],"the_end",7) NEQ 0 ; j++)
{
compile(pattern_test[j],pbuf_test);
start_ptr = loca_loop.end_ptr;
ligne = loca_loop.line_no;
loca_tst = find_keyword(start_ptr, ligne, end_line, pbuf_test);
while ((loca_tst.line_no NEQ 0) AND (loca_tst.end_ptr < l_end_tst.end_ptr))
{
nb_expl_tst++;
start_ptr = loca_tst.end_ptr;
ligne = loca_tst.line_no;
loca_tst = find_keyword(start_ptr, ligne, end_line, pbuf_test);
}
}
/*------ if not enough explicit tests ---------------------------------*/
if ( nb_expl_tst NEQ nb_tst)
fprintf( fout_ptr ,"\nWARNING (line %4ld) : do please use explicit test(s). ",loca_loop.line_no);
/*----- look for assignement ------------------------------------------*/
start_ptr = loca_loop.end_ptr;
ligne = loca_loop.line_no;
compile("[^><=!]=[^=]",pbuf_test);
loca_tst = find_keyword(start_ptr, ligne, end_line, pbuf_test);
if ((loca_tst.end_ptr < l_end_tst.end_ptr) AND (loca_tst.end_ptr NEQ NULL))
fprintf(fout_ptr,"\nWARNING (line %4ld) : assignement in control flow statement should be avoided.",loca_tst.line_no);
/*----- look for use of zero as a pointer value ----------------------*/
compile("[^*][a-z0-9_]+_ptr *N*EQ +0",pbuf_test);
loca_tst = find_keyword(start_ptr, ligne, end_line, pbuf_test);
if ((loca_tst.end_ptr < l_end_tst.end_ptr) AND (loca_tst.end_ptr NEQ NULL))
fprintf(fout_ptr,"\nWARNING (line %4ld) : pointer value 0 shall be implemented via the pointer constant NULL.",loca_tst.line_no);
/*----- next loop of the same type -----------------------------------*/
loca_loop = find_keyword(start_ptr, ligne, nb_line, pbuf_loop);
nb_tst = 1;
nb_expl_tst = 0;
}
start_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void lib_fct_call(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : lib_fct_call **
** VERSION : 001 **
** LONG_NAME : library function call **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : lib_fct_call looks for each call of a library **
** function that is not immediately followed by **
** an if statement and prints a warning in fout_ptr **
** if a match is found in source_file[]. **
** **
** REMARKS : this function does not print a warning if there is **
** an if-statement but no test of the returned value. **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf1[PMAX]; /* compiled pattern : function called */
CHAR pbuf2[PMAX]; /* compiled pattern : test if */
CHAR pbuf3[PMAX]; /* compiled pattern : any but space */
T_LOCA loca_call; /* current location of call */
T_LOCA loca_test; /* current location of test (if) */
T_LOCA loca_sth; /* current location of sth unexpected */
LONG i; /* universal counter */
LONG ligne; /* start of the search */
CHAR *start_ptr; /* start of the search */
/*----------- Initialize variables --------------------------------------------*/
CHAR *pattern_ptr[] = /* patterns of functions returning status value */
{
"malloc(.+;","calloc(.+;","realloc(.+;",
"alloca(.+;","_fmalloc(.+;","halloc(.+;", /* 3 non ANSI std fctions */
"strdup(.+;",
"fopen(.+;",
"the end"
};
start_ptr = source_file; /* first line */
ligne = 1;
compile("^ *if[ (]",pbuf2);
compile("[¡-ÿ!-~]",pbuf3); /* ASCII : any char but space */
/*----------- Look for each library function call -----------------------------*/
for ( i=0 ; strncmp(pattern_ptr[i],"the end",7) NEQ 0 ; i++ )
{
compile(pattern_ptr[i],pbuf1);
loca_call = find_keyword(start_ptr, ligne, nb_line, pbuf1);
while (loca_call.end_ptr NEQ NULL)
{
start_ptr = loca_call.end_ptr;
ligne = loca_call.line_no;
loca_test = find_keyword(start_ptr, ligne, nb_line, pbuf2);
loca_sth = find_keyword(start_ptr, ligne, nb_line, pbuf3);
/*---- warning if there is no if just after the call --------------------*/
if ((loca_test.line_no EQ 0) OR (loca_sth.line_no < loca_test.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : the status information returned by this",loca_call.line_no);
fprintf(fout_ptr," library function should be checked for validity before use.");
}
loca_call = find_keyword(start_ptr, ligne, nb_line, pbuf1);
}
start_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}
void val_and_ad(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : val_and_ad **
** VERSION : 001 **
** LONG_NAME : value and address of an object in the same line **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : val_and_ad() looks for an address (expression **
** starting with &) reads the corresponding variable **
** name and look for the variable (not preceeded by &)**
** in the same line. If a match is found, a warning **
** is printed in output file fout_ptr. **
** **
** REMARKS : val_and_ad() only checks addresses starting with & **
** followed by lowercase letters, digits and **
** underscores. **
** **
** FUNCTIONS : compile(), find_keyword(), fprintf(), strncpy(), **
** strncat() **
** **
** GLOBALS : source_file[] **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR *start_ptr; /* place to start the search */
LONG ligne; /* current line */
LONG end_line; /* line to end the search */
CHAR *s_ptr; /* pointer in source_file[] */
CHAR *end_ptr; /* end of address */
T_LOCA l_add; /* current location of address */
T_LOCA l_val; /* current location of value */
CHAR padd[PMAX]; /* pattern template : address */
CHAR pval[PMAX]; /* pattern template : value */
CHAR sval[LINLEN]; /* value : pattern to compile */
/*--------- Initialize variables --------------------------------------------*/
start_ptr = source_file;
ligne = 1;
compile("[^&]&:v", padd);
/*--------- Scan source_file[] looking for addresses ------------------------*/
l_add = find_keyword(start_ptr, ligne, nb_line, padd); /* first match */
while ( l_add.line_no NEQ 0 ) /* while address found */
{
ligne = l_add.line_no;
start_ptr = l_add.end_ptr;
strncpy(sval,"[ (+*-/=[]",11); /* left of value pattern */
if (ligne < (nb_line-1)) /* useful for speed */
end_line = ligne +1;
else
end_line = nb_line;
/*----- back to start of line (place to start the value search) ----------*/
do
{
start_ptr--;
}while( *(start_ptr -1) NEQ '\0');
/*----- find variable name -----------------------------------------------*/
s_ptr = l_add.end_ptr -1; /* start of name */
end_ptr = s_ptr;
do /* go further til end of name found */
{
end_ptr++;
}while (((*end_ptr < '9') AND (*end_ptr > '0')) OR ((*end_ptr > 'a') AND (*end_ptr < 'z')) OR (*end_ptr EQ '_' ));
strncat(sval, s_ptr, (BITFIELD)(end_ptr - s_ptr));/* add var name in sval */
strncat(sval,"[ +-*/=);\\]]",14); /* add after var name */
/*---- compile and try to find value of var in the same line -------------*/
compile(sval,pval);
l_val = find_keyword(start_ptr, ligne, end_line, pval);
if ( l_val.line_no EQ l_add.line_no ) /* if match found */
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : it is better to avoid using both value",l_val.line_no);
fprintf(fout_ptr," and address of an object in the same statement.");
}
start_ptr = l_add.end_ptr;
l_add = find_keyword(start_ptr, ligne, nb_line, padd); /* next add */
}
}
void miscellaneous(CHAR source_file[], LONG nb_line, FILE *fout_ptr)
/**C*F*******************************************************************
** **
** SRC-MODULE : miscellaneous **
** VERSION : 001 **
** LONG_NAME : miscellaneous **
** **
** **
** SPECIFICATION : C coding conventions **
** SUBSYSTEM : - **
** SYSTEM_TYPE : PCD-3T **
** **
** AUTHOR : Helene Ballay **
** SUBSTITUTE : Dr. Rainer Storn **
** **
** DESCRIPTION : miscellaneous() checks the presence of definition **
** of an enumeration type within a structure, of **
** constants 0 or 0x whose name doesn't start with M_,**
** and of the ? : operators, and prints a warning in **
** fout_ptr if match is found. **
** **
** REMARKS : '? is not taken into account as it is assumed **
** that the statement is parenthesized and it might **
** not be the ?-C operator (e.g." case '?' : ") **
** **
** FUNCTIONS : strncmp(), compile(), find_keyword(), fprintf() **
** **
** GLOBALS : source_file[] **
** **
** PARAMETERS : nb_line :number of lines to examine in source_file **
** fout_ptr:points to output file **
** **
** PRECONDITIONS : source_file[] must contain an ASCII file with all **
** '\n' replaced by '\0'. **
** **
** POSTCONDITIONS : file pointed to by fout_ptr will contain results **
** of checking process. **
** **
** **
***C*F*E****************************************************************/
{
CHAR pbuf1[PMAX]; /* first compiled pattern */
CHAR pbuf2[PMAX]; /* second pattern compiled */
CHAR pbuf3[PMAX]; /* ev. third pattern compiled */
LONG i; /* universal counter */
CHAR *start_ptr; /* start of the search */
LONG ligne; /* start of the search */
LONG end_line; /* end of search */
T_LOCA loca_1; /* current loca of first keyword */
T_LOCA loca_2; /* current loca of second keyword */
T_LOCA loca_3; /* current loca of third keyword */
/*----------- Initialize variables --------------------------------------------*/
CHAR *pattern[]= /* first patterns to compile */
{
"^ *struct ","#define ",
"[^']?",
"the_end"
};
CHAR *patt2[]= /* second patterns to compile */
{
"}"," 0[1-9x]",
"\\:"
};
CHAR *patt3[]= /* third patterns to compile */
{
" enum .*{", "M_"
};
start_ptr = source_file; /* first line */
ligne = 1;
/*----------- Look for each expression ----------------------------------------*/
for ( i = 0 ; strncmp(pattern[i],"the_end",7) NEQ 0 ; i++ )
{
compile(pattern[i],pbuf1);
compile(patt2[i],pbuf2);
loca_1 = find_keyword(start_ptr, ligne, nb_line, pbuf1);
if ( i<2 ) /* struct and enum, or mask */
{ /* need a third pattern */
compile(patt3[i],pbuf3);
}
/*----- check each first pattern -----------------------------------------*/
while (loca_1.line_no NEQ 0) /* while first term found */
{
start_ptr = loca_1.end_ptr;
ligne = loca_1.line_no;
if ( (i>0) AND (ligne < nb_line-1)) /* useful for speed : except */
end_line = ligne + 1; /* struct-enum, don't need to */
else /* search the other patterns */
end_line = nb_line; /* in an other line */
loca_2 = find_keyword(start_ptr, ligne, end_line, pbuf2);
if (i < 2) /* struct-enum or mask */
{
loca_3 = find_keyword(start_ptr, ligne, end_line, pbuf3);
if ((i EQ 0) AND (loca_3.line_no NEQ 0) AND (loca_3.line_no < loca_2.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : You shouldn't define an enumeration type ",loca_3.line_no);
fprintf(fout_ptr,"within a structure.");
}
if ((i EQ 1) AND (loca_2.line_no EQ loca_1.line_no) AND (loca_3.line_no NEQ loca_2.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : if this constant is serving as bit mask ",loca_1.line_no);
fprintf(fout_ptr,"its name should start with M_ ");
}
}
else if ((i EQ 2) AND (loca_1.line_no NEQ 0) AND (loca_1.line_no EQ loca_2.line_no))
{
fprintf(fout_ptr,"\nWARNING (line %4ld) : it is strongly recommended not to use ",loca_1.line_no);
fprintf(fout_ptr,"C's ?-operator but to use if...else constructs if possible.");
}
loca_1 = find_keyword(start_ptr, ligne, nb_line, pbuf1);
}
start_ptr = source_file;
ligne = 1; /* go back to beginning of source_file[] */
}
}